/*-------------------------------------------------------------------------
 *
 * jsonb.c
 *		jsonb 类型的 I/O 例程
 *
 * Copyright (c) 2014-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/backend/utils/adt/jsonb.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/htup_details.h"
#include "access/transam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/json.h"
#include "utils/jsonb.h"
#include "utils/jsonfuncs.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"

typedef struct JsonbInState
{
	JsonbParseState *parseState;
	JsonbValue *res;
} JsonbInState;

/* 与 json 分类不同，我们需要对 json 和 jsonb 进行不同处理 */
typedef enum					/* datum_to_jsonb 的类型分类 */
{
	JSONBTYPE_NULL,				/* null，因此我们没有费心去识别 */
	JSONBTYPE_BOOL,				/* 布尔值（仅限内置类型） */
	JSONBTYPE_NUMERIC,			/* 数值（同上） */
	JSONBTYPE_DATE,				/* 我们对日期时间使用特殊格式 */
	JSONBTYPE_TIMESTAMP,		/* 我们对时间戳使用特殊格式 */
	JSONBTYPE_TIMESTAMPTZ,		/* ... 和 timestamptz */
	JSONBTYPE_JSON,				/* JSON */
	JSONBTYPE_JSONB,			/* JSONB */
	JSONBTYPE_ARRAY,			/* array */
	JSONBTYPE_COMPOSITE,		/* 复合类型 */
	JSONBTYPE_JSONCAST,			/* 显式转换为JSON的某种东西 */
	JSONBTYPE_OTHER				/* all else */
} JsonbTypeCategory;

typedef struct JsonbAggState
{
	JsonbInState *res;
	JsonbTypeCategory key_category;
	Oid			key_output_func;
	JsonbTypeCategory val_category;
	Oid			val_output_func;
} JsonbAggState;

static inline Datum fc_jsonb_from_cstring(char *fc_json, int fc_len);
static size_t fc_checkStringLen(size_t fc_len);
static void fc_jsonb_in_object_start(void *fc_pstate);
static void fc_jsonb_in_object_end(void *fc_pstate);
static void fc_jsonb_in_array_start(void *fc_pstate);
static void fc_jsonb_in_array_end(void *fc_pstate);
static void fc_jsonb_in_object_field_start(void *fc_pstate, char *fc_fname, bool fc_isnull);
static void fc_jsonb_put_escaped_value(StringInfo fc_out, JsonbValue *fc_scalarVal);
static void fc_jsonb_in_scalar(void *fc_pstate, char *fc_token, JsonTokenType fc_tokentype);
static void fc_jsonb_categorize_type(Oid fc_typoid,
								  JsonbTypeCategory *fc_tcategory,
								  Oid *fc_outfuncoid);
static void fc_composite_to_jsonb(Datum fc_composite, JsonbInState *fc_result);
static void fc_array_dim_to_jsonb(JsonbInState *fc_result, int fc_dim, int fc_ndims, int *fc_dims,
							   Datum *fc_vals, bool *fc_nulls, int *fc_valcount,
							   JsonbTypeCategory fc_tcategory, Oid fc_outfuncoid);
static void fc_array_to_jsonb_internal(Datum fc_array, JsonbInState *fc_result);
static void fc_jsonb_categorize_type(Oid fc_typoid,
								  JsonbTypeCategory *fc_tcategory,
								  Oid *fc_outfuncoid);
static void fc_datum_to_jsonb(Datum fc_val, bool fc_is_null, JsonbInState *fc_result,
						   JsonbTypeCategory fc_tcategory, Oid fc_outfuncoid,
						   bool fc_key_scalar);
static void add_jsonb(Datum fc_val, bool fc_is_null, JsonbInState *fc_result,
					  Oid fc_val_type, bool fc_key_scalar);
static JsonbParseState *fc_clone_parse_state(JsonbParseState *fc_state);
static char *fc_JsonbToCStringWorker(StringInfo fc_out, JsonbContainer *fc_in, int fc_estimated_len, bool fc_indent);
static void add_indent(StringInfo fc_out, bool fc_indent, int fc_level);

/*
 * jsonb 类型输入函数
 */
Datum jsonb_in(PG_FUNCTION_ARGS)
{
	char	   *fc_json = PG_GETARG_CSTRING(0);

	return fc_jsonb_from_cstring(fc_json, strlen(fc_json));
}

/*
 * jsonb 类型接收函数
 *
 * 类型作为文本在二进制模式下发送，因此这几乎与输入函数相同，但带有版本号的前缀，以便我们
 * 在必要时可以改变未来发送的二进制格式。目前，仅支持版本 1。
 */
Datum jsonb_recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);
	int			fc_version = pq_getmsgint(fc_buf, 1);
	char	   *fc_str;
	int			fc_nbytes;

	if (fc_version == 1)
		fc_str = pq_getmsgtext(fc_buf, fc_buf->len - fc_buf->cursor, &fc_nbytes);
	else
		elog(ERROR, "unsupported jsonb version number %d", fc_version);

	return fc_jsonb_from_cstring(fc_str, fc_nbytes);
}

/*
 * jsonb 类型输出函数
 */
Datum jsonb_out(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	char	   *fc_out;

	fc_out = JsonbToCString(NULL, &fc_jb->root, VARSIZE(fc_jb));

	PG_RETURN_CSTRING(fc_out);
}

/*
 * jsonb 类型发送函数
 *
 * 只需将 jsonb 作为一个版本号发送，然后是一个文本字符串
 */
Datum jsonb_send(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_jb = PG_GETARG_JSONB_P(0);
	StringInfoData fc_buf;
	StringInfo	fc_jtext = makeStringInfo();
	int			fc_version = 1;

	(void) JsonbToCString(fc_jtext, &fc_jb->root, VARSIZE(fc_jb));

	pq_begintypsend(&fc_buf);
	pq_sendint8(&fc_buf, fc_version);
	pq_sendtext(&fc_buf, fc_jtext->data, fc_jtext->len);
	pfree(fc_jtext->data);
	pfree(fc_jtext);

	PG_RETURN_BYTEA_P(pq_endtypsend(&fc_buf));
}

/*
 * 获取 jsonb 容器的类型名称。
 */
static const char * fc_JsonbContainerTypeName(JsonbContainer *fc_jbc)
{
	JsonbValue	fc_scalar;

	if (JsonbExtractScalar(fc_jbc, &fc_scalar))
		return JsonbTypeName(&fc_scalar);
	else if (JsonContainerIsArray(fc_jbc))
		return "array";
	else if (JsonContainerIsObject(fc_jbc))
		return "object";
	else
	{
		elog(ERROR, "invalid jsonb container type: 0x%08x", fc_jbc->header);
		return "unknown";
	}
}

/*
 * 获取 jsonb 值的类型名称。
 */
const char * JsonbTypeName(JsonbValue *fc_jbv)
{
	switch (fc_jbv->type)
	{
		case jbvBinary:
			return fc_JsonbContainerTypeName(fc_jbv->val.binary.data);
		case jbvObject:
			return "object";
		case jbvArray:
			return "array";
		case jbvNumeric:
			return "number";
		case jbvString:
			return "string";
		case jbvBool:
			return "boolean";
		case jbvNull:
			return "null";
		case jbvDatetime:
			switch (fc_jbv->val.datetime.typid)
			{
				case DATEOID:
					return "date";
				case TIMEOID:
					return "time without time zone";
				case TIMETZOID:
					return "time with time zone";
				case TIMESTAMPOID:
					return "timestamp without time zone";
				case TIMESTAMPTZOID:
					return "timestamp with time zone";
				default:
					elog(ERROR, "unrecognized jsonb value datetime type: %d",
						 fc_jbv->val.datetime.typid);
			}
			return "unknown";
		default:
			elog(ERROR, "unrecognized jsonb value type: %d", fc_jbv->type);
			return "unknown";
	}
}

/*
 * SQL 函数 jsonb_typeof(jsonb) -> text
 *
 * 此函数在此处是因为对应的 json 函数在 json.c 中，因为它使用了在其他地方没有暴露的 json 解析器内部。
 */
Datum jsonb_typeof(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	const char *fc_result = fc_JsonbContainerTypeName(&fc_in->root);

	PG_RETURN_TEXT_P(cstring_to_text(fc_result));
}

/*
 * jsonb_from_cstring
 *
 * 将 json 字符串转换为 jsonb Datum。
 *
 * 使用 json 解析器（带钩子）构建 jsonb。
 */
static inline Datum
fc_jsonb_from_cstring(char *fc_json, int fc_len)
{
	JsonLexContext *fc_lex;
	JsonbInState fc_state;
	JsonSemAction fc_sem;

	memset(&fc_state, 0, sizeof(fc_state));
	memset(&fc_sem, 0, sizeof(fc_sem));
	fc_lex = makeJsonLexContextCstringLen(fc_json, fc_len, GetDatabaseEncoding(), true);

	fc_sem.semstate = (void *) &fc_state;

	fc_sem.object_start = fc_jsonb_in_object_start;
	fc_sem.array_start = fc_jsonb_in_array_start;
	fc_sem.object_end = fc_jsonb_in_object_end;
	fc_sem.array_end = fc_jsonb_in_array_end;
	fc_sem.scalar = fc_jsonb_in_scalar;
	fc_sem.object_field_start = fc_jsonb_in_object_field_start;

	pg_parse_json_or_ereport(fc_lex, &fc_sem);

	/* 解析后，项成员具有组合的 jsonb 结构 */
	PG_RETURN_POINTER(JsonbValueToJsonb(fc_state.res));
}

static size_t fc_checkStringLen(size_t fc_len)
{
	if (fc_len > JENTRY_OFFLENMASK)
		ereport(ERROR,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg("string too long to represent as jsonb string"),
				 errdetail("Due to an implementation restriction, jsonb strings cannot exceed %d bytes.",
						   JENTRY_OFFLENMASK)));

	return fc_len;
}

static void fc_jsonb_in_object_start(void *fc_pstate)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;

	fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_BEGIN_OBJECT, NULL);
}

static void fc_jsonb_in_object_end(void *fc_pstate)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;

	fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_END_OBJECT, NULL);
}

static void fc_jsonb_in_array_start(void *fc_pstate)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;

	fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_BEGIN_ARRAY, NULL);
}

static void fc_jsonb_in_array_end(void *fc_pstate)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;

	fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_END_ARRAY, NULL);
}

static void fc_jsonb_in_object_field_start(void *fc_pstate, char *fc_fname, bool fc_isnull)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;
	JsonbValue	fc_v;

	Assert(fc_fname != NULL);
	fc_v.type = jbvString;
	fc_v.val.string.len = fc_checkStringLen(strlen(fc_fname));
	fc_v.val.string.val = fc_fname;

	fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_KEY, &fc_v);
}

static void fc_jsonb_put_escaped_value(StringInfo fc_out, JsonbValue *fc_scalarVal)
{
	switch (fc_scalarVal->type)
	{
		case jbvNull:
			appendBinaryStringInfo(fc_out, "null", 4);
			break;
		case jbvString:
			escape_json(fc_out, pnstrdup(fc_scalarVal->val.string.val, fc_scalarVal->val.string.len));
			break;
		case jbvNumeric:
			appendStringInfoString(fc_out,
								   DatumGetCString(DirectFunctionCall1(numeric_out,
																	   PointerGetDatum(fc_scalarVal->val.numeric))));
			break;
		case jbvBool:
			if (fc_scalarVal->val.boolean)
				appendBinaryStringInfo(fc_out, "true", 4);
			else
				appendBinaryStringInfo(fc_out, "false", 5);
			break;
		default:
			elog(ERROR, "unknown jsonb scalar type");
	}
}

/*
 * 对于 jsonb，我们始终需要未转义的值 - 这就是标记中的内容
 */
static void fc_jsonb_in_scalar(void *fc_pstate, char *fc_token, JsonTokenType fc_tokentype)
{
	JsonbInState *fc__state = (JsonbInState *) fc_pstate;
	JsonbValue	fc_v;
	Datum		fc_numd;

	switch (fc_tokentype)
	{

		case JSON_TOKEN_STRING:
			Assert(fc_token != NULL);
			fc_v.type = jbvString;
			fc_v.val.string.len = fc_checkStringLen(strlen(fc_token));
			fc_v.val.string.val = fc_token;
			break;
		case JSON_TOKEN_NUMBER:

			/*
			 * 无需检查数字值的大小，因为最大数字大小远低于 JsonbValue 限制
			 */
			Assert(fc_token != NULL);
			fc_v.type = jbvNumeric;
			fc_numd = DirectFunctionCall3(numeric_in,
									   CStringGetDatum(fc_token),
									   ObjectIdGetDatum(InvalidOid),
									   Int32GetDatum(-1));
			fc_v.val.numeric = DatumGetNumeric(fc_numd);
			break;
		case JSON_TOKEN_TRUE:
			fc_v.type = jbvBool;
			fc_v.val.boolean = true;
			break;
		case JSON_TOKEN_FALSE:
			fc_v.type = jbvBool;
			fc_v.val.boolean = false;
			break;
		case JSON_TOKEN_NULL:
			fc_v.type = jbvNull;
			break;
		default:
			/* 不应该可以 */
			elog(ERROR, "invalid json token type");
			break;
	}

	if (fc__state->parseState == NULL)
	{
		/* 单一标量 */
		JsonbValue	fc_va;

		fc_va.type = jbvArray;
		fc_va.val.array.rawScalar = true;
		fc_va.val.array.nElems = 1;

		fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_BEGIN_ARRAY, &fc_va);
		fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_ELEM, &fc_v);
		fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_END_ARRAY, NULL);
	}
	else
	{
		JsonbValue *fc_o = &fc__state->parseState->contVal;

		switch (fc_o->type)
		{
			case jbvArray:
				fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_ELEM, &fc_v);
				break;
			case jbvObject:
				fc__state->res = pushJsonbValue(&fc__state->parseState, WJB_VALUE, &fc_v);
				break;
			default:
				elog(ERROR, "unexpected parent of nested structure");
		}
	}
}

/*
 * JsonbToCString
 *	   将 jsonb 值转换为 C 字符串。
 *
 * 如果 'out' 参数非空，结果 C 字符串将存储在
 * StringBuffer 中。结果字符串始终被返回。
 *
 * 传递 StringInfo 而不是 NULL 的典型情况是调用者希望在不调用 strlen 的情况下访问 len 属性，例如，
 * 如果他们要将其转换为 text* 对象。
 */
char * JsonbToCString(StringInfo fc_out, JsonbContainer *fc_in, int fc_estimated_len)
{
	return fc_JsonbToCStringWorker(fc_out, fc_in, fc_estimated_len, false);
}

/*
 * 同样的事情，但启用了缩进
 */
char * JsonbToCStringIndent(StringInfo fc_out, JsonbContainer *fc_in, int fc_estimated_len)
{
	return fc_JsonbToCStringWorker(fc_out, fc_in, fc_estimated_len, true);
}

/*
 * 上述两个函数的通用工作
 */
static char * fc_JsonbToCStringWorker(StringInfo fc_out, JsonbContainer *fc_in, int fc_estimated_len, bool fc_indent)
{
	bool		fc_first = true;
	JsonbIterator *fc_it;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_type = WJB_DONE;
	int			fc_level = 0;
	bool		fc_redo_switch = false;

	/* 如果我们在缩进，请不要在逗号后添加空格 */
	int			fc_ispaces = fc_indent ? 1 : 2;

	/*
	 * 不要缩进第一个项目。这将在循环底部设置为缩进标志。
	 */
	bool		fc_use_indent = false;
	bool		fc_raw_scalar = false;
	bool		fc_last_was_key = false;

	if (fc_out == NULL)
		fc_out = makeStringInfo();

	enlargeStringInfo(fc_out, (fc_estimated_len >= 0) ? fc_estimated_len : 64);

	fc_it = JsonbIteratorInit(fc_in);

	while (fc_redo_switch ||
		   ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE))
	{
		fc_redo_switch = false;
		switch (fc_type)
		{
			case WJB_BEGIN_ARRAY:
				if (!fc_first)
					appendBinaryStringInfo(fc_out, ", ", fc_ispaces);

				if (!fc_v.val.array.rawScalar)
				{
					add_indent(fc_out, fc_use_indent && !fc_last_was_key, fc_level);
					appendStringInfoCharMacro(fc_out, '[');
				}
				else
					fc_raw_scalar = true;

				fc_first = true;
				fc_level++;
				break;
			case WJB_BEGIN_OBJECT:
				if (!fc_first)
					appendBinaryStringInfo(fc_out, ", ", fc_ispaces);

				add_indent(fc_out, fc_use_indent && !fc_last_was_key, fc_level);
				appendStringInfoCharMacro(fc_out, '{');

				fc_first = true;
				fc_level++;
				break;
			case WJB_KEY:
				if (!fc_first)
					appendBinaryStringInfo(fc_out, ", ", fc_ispaces);
				fc_first = true;

				add_indent(fc_out, fc_use_indent, fc_level);

				/* json 规则保证这是一个字符串 */
				fc_jsonb_put_escaped_value(fc_out, &fc_v);
				appendBinaryStringInfo(fc_out, ": ", 2);

				fc_type = JsonbIteratorNext(&fc_it, &fc_v, false);
				if (fc_type == WJB_VALUE)
				{
					fc_first = false;
					fc_jsonb_put_escaped_value(fc_out, &fc_v);
				}
				else
				{
					Assert(fc_type == WJB_BEGIN_OBJECT || fc_type == WJB_BEGIN_ARRAY);

					/*
					 * 我们需要重新运行当前 switch()，因为我们需要
					 * 输出我们刚从迭代器获得的对象
					 * 然后再调用迭代器。
					 */
					fc_redo_switch = true;
				}
				break;
			case WJB_ELEM:
				if (!fc_first)
					appendBinaryStringInfo(fc_out, ", ", fc_ispaces);
				fc_first = false;

				if (!fc_raw_scalar)
					add_indent(fc_out, fc_use_indent, fc_level);
				fc_jsonb_put_escaped_value(fc_out, &fc_v);
				break;
			case WJB_END_ARRAY:
				fc_level--;
				if (!fc_raw_scalar)
				{
					add_indent(fc_out, fc_use_indent, fc_level);
					appendStringInfoCharMacro(fc_out, ']');
				}
				fc_first = false;
				break;
			case WJB_END_OBJECT:
				fc_level--;
				add_indent(fc_out, fc_use_indent, fc_level);
				appendStringInfoCharMacro(fc_out, '}');
				fc_first = false;
				break;
			default:
				elog(ERROR, "unknown jsonb iterator token type");
		}
		fc_use_indent = fc_indent;
		fc_last_was_key = fc_redo_switch;
	}

	Assert(fc_level == 0);

	return fc_out->data;
}

static void add_indent(StringInfo fc_out, bool fc_indent, int fc_level)
{
	if (fc_indent)
	{
		int			fc_i;

		appendStringInfoCharMacro(fc_out, '\n');
		for (fc_i = 0; fc_i < fc_level; fc_i++)
			appendBinaryStringInfo(fc_out, "    ", 4);
	}
}


/*
 * 确定我们希望如何在 datum_to_jsonb 中呈现给定类型的值。
 *
 * 给定数据类型 OID，返回其 JsonbTypeCategory，以及类型的
 * 输出函数 OID。如果返回的类别是 JSONBTYPE_JSONCAST，
 * 我们返回相关转换函数的 OID。
 */
static void fc_jsonb_categorize_type(Oid fc_typoid,
					  JsonbTypeCategory *fc_tcategory,
					  Oid *fc_outfuncoid)
{
	bool		fc_typisvarlena;

	/* 查看任何域 */
	fc_typoid = getBaseType(fc_typoid);

	*fc_outfuncoid = InvalidOid;

	/*
	 * 我们需要获取除日期和时间戳类型、布尔值、数组和复合类型、json 和 jsonb 之外的所有类型的输出函数，
	 * 以及那些有转换为 json 的非内置类型。在最后一种情况下，
	 * 我们返回转换函数的 oid。
	 */

	switch (fc_typoid)
	{
		case BOOLOID:
			*fc_tcategory = JSONBTYPE_BOOL;
			break;

		case INT2OID:
		case INT4OID:
		case INT8OID:
		case FLOAT4OID:
		case FLOAT8OID:
		case NUMERICOID:
			getTypeOutputInfo(fc_typoid, fc_outfuncoid, &fc_typisvarlena);
			*fc_tcategory = JSONBTYPE_NUMERIC;
			break;

		case DATEOID:
			*fc_tcategory = JSONBTYPE_DATE;
			break;

		case TIMESTAMPOID:
			*fc_tcategory = JSONBTYPE_TIMESTAMP;
			break;

		case TIMESTAMPTZOID:
			*fc_tcategory = JSONBTYPE_TIMESTAMPTZ;
			break;

		case JSONBOID:
			*fc_tcategory = JSONBTYPE_JSONB;
			break;

		case JSONOID:
			*fc_tcategory = JSONBTYPE_JSON;
			break;

		default:
			/* 检查数组和复合类型 */
			if (OidIsValid(get_element_type(fc_typoid)) || fc_typoid == ANYARRAYOID
				|| fc_typoid == ANYCOMPATIBLEARRAYOID || fc_typoid == RECORDARRAYOID)
				*fc_tcategory = JSONBTYPE_ARRAY;
			else if (type_is_rowtype(fc_typoid))	/* 包括RECORDOID */
				*fc_tcategory = JSONBTYPE_COMPOSITE;
			else
			{
				/* 这可能是一般情况... */
				*fc_tcategory = JSONBTYPE_OTHER;

				/*
				 * 但首先让我们查找转换为 json（注意：不是转换为
				 * jsonb），如果它不是内置的。
				 */
				if (fc_typoid >= FirstNormalObjectId)
				{
					Oid			fc_castfunc;
					CoercionPathType fc_ctype;

					fc_ctype = find_coercion_pathway(JSONOID, fc_typoid,
												  COERCION_EXPLICIT, &fc_castfunc);
					if (fc_ctype == COERCION_PATH_FUNC && OidIsValid(fc_castfunc))
					{
						*fc_tcategory = JSONBTYPE_JSONCAST;
						*fc_outfuncoid = fc_castfunc;
					}
					else
					{
						/* 不是转换类型，所以只需获取通常的输出函数 */
						getTypeOutputInfo(fc_typoid, fc_outfuncoid, &fc_typisvarlena);
					}
				}
				else
				{
					/* 任何其他内置类型 */
					getTypeOutputInfo(fc_typoid, fc_outfuncoid, &fc_typisvarlena);
				}
				break;
			}
	}
}

/*
 * 将 Datum 转换为 jsonb，将其添加到结果 JsonbInState 中。
 *
 * tcategory 和 outfuncoid 是来自先前调用 json_categorize_type 的，
 * 除非 is_null 为 true，否则它们可能无效。
 *
 * 如果 key_scalar 为 true，则值作为键存储，因此必须确保
 * 它是可接受的类型，并强制其为 jbvString。
 */
static void fc_datum_to_jsonb(Datum fc_val, bool fc_is_null, JsonbInState *fc_result,
			   JsonbTypeCategory fc_tcategory, Oid fc_outfuncoid,
			   bool fc_key_scalar)
{
	char	   *fc_outputstr;
	bool		fc_numeric_error;
	JsonbValue	fc_jb;
	bool		fc_scalar_jsonb = false;

	check_stack_depth();

	/* 将 val 转换为 jb 中的 JsonbValue（在大多数情况下） */
	if (fc_is_null)
	{
		Assert(!fc_key_scalar);
		fc_jb.type = jbvNull;
	}
	else if (fc_key_scalar &&
			 (fc_tcategory == JSONBTYPE_ARRAY ||
			  fc_tcategory == JSONBTYPE_COMPOSITE ||
			  fc_tcategory == JSONBTYPE_JSON ||
			  fc_tcategory == JSONBTYPE_JSONB ||
			  fc_tcategory == JSONBTYPE_JSONCAST))
	{
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("key value must be scalar, not array, composite, or json")));
	}
	else
	{
		if (fc_tcategory == JSONBTYPE_JSONCAST)
			fc_val = OidFunctionCall1(fc_outfuncoid, fc_val);

		switch (fc_tcategory)
		{
			case JSONBTYPE_ARRAY:
				fc_array_to_jsonb_internal(fc_val, fc_result);
				break;
			case JSONBTYPE_COMPOSITE:
				fc_composite_to_jsonb(fc_val, fc_result);
				break;
			case JSONBTYPE_BOOL:
				if (fc_key_scalar)
				{
					fc_outputstr = DatumGetBool(fc_val) ? "true" : "false";
					fc_jb.type = jbvString;
					fc_jb.val.string.len = strlen(fc_outputstr);
					fc_jb.val.string.val = fc_outputstr;
				}
				else
				{
					fc_jb.type = jbvBool;
					fc_jb.val.boolean = DatumGetBool(fc_val);
				}
				break;
			case JSONBTYPE_NUMERIC:
				fc_outputstr = OidOutputFunctionCall(fc_outfuncoid, fc_val);
				if (fc_key_scalar)
				{
					/* 始终引用键 */
					fc_jb.type = jbvString;
					fc_jb.val.string.len = strlen(fc_outputstr);
					fc_jb.val.string.val = fc_outputstr;
				}
				else
				{
					/*
					 * 如果它是有效的 JSON 数字，则将其设置为数字，否则
					 * 作为字符串。无效的数字输出将始终包含 'N' 或 'n'（我觉得）。
					 */
					fc_numeric_error = (strchr(fc_outputstr, 'N') != NULL ||
									 strchr(fc_outputstr, 'n') != NULL);
					if (!fc_numeric_error)
					{
						Datum		fc_numd;

						fc_jb.type = jbvNumeric;
						fc_numd = DirectFunctionCall3(numeric_in,
												   CStringGetDatum(fc_outputstr),
												   ObjectIdGetDatum(InvalidOid),
												   Int32GetDatum(-1));
						fc_jb.val.numeric = DatumGetNumeric(fc_numd);
						pfree(fc_outputstr);
					}
					else
					{
						fc_jb.type = jbvString;
						fc_jb.val.string.len = strlen(fc_outputstr);
						fc_jb.val.string.val = fc_outputstr;
					}
				}
				break;
			case JSONBTYPE_DATE:
				fc_jb.type = jbvString;
				fc_jb.val.string.val = JsonEncodeDateTime(NULL, fc_val,
													   DATEOID, NULL);
				fc_jb.val.string.len = strlen(fc_jb.val.string.val);
				break;
			case JSONBTYPE_TIMESTAMP:
				fc_jb.type = jbvString;
				fc_jb.val.string.val = JsonEncodeDateTime(NULL, fc_val,
													   TIMESTAMPOID, NULL);
				fc_jb.val.string.len = strlen(fc_jb.val.string.val);
				break;
			case JSONBTYPE_TIMESTAMPTZ:
				fc_jb.type = jbvString;
				fc_jb.val.string.val = JsonEncodeDateTime(NULL, fc_val,
													   TIMESTAMPTZOID, NULL);
				fc_jb.val.string.len = strlen(fc_jb.val.string.val);
				break;
			case JSONBTYPE_JSONCAST:
			case JSONBTYPE_JSON:
				{
					/* 将 json 直接解析到现有结果对象中 */
					JsonLexContext *fc_lex;
					JsonSemAction fc_sem;
					text	   *fc_json = DatumGetTextPP(fc_val);

					fc_lex = makeJsonLexContext(fc_json, true);

					memset(&fc_sem, 0, sizeof(fc_sem));

					fc_sem.semstate = (void *) fc_result;

					fc_sem.object_start = fc_jsonb_in_object_start;
					fc_sem.array_start = fc_jsonb_in_array_start;
					fc_sem.object_end = fc_jsonb_in_object_end;
					fc_sem.array_end = fc_jsonb_in_array_end;
					fc_sem.scalar = fc_jsonb_in_scalar;
					fc_sem.object_field_start = fc_jsonb_in_object_field_start;

					pg_parse_json_or_ereport(fc_lex, &fc_sem);
				}
				break;
			case JSONBTYPE_JSONB:
				{
					Jsonb	   *fc_jsonb = DatumGetJsonbP(fc_val);
					JsonbIterator *fc_it;

					fc_it = JsonbIteratorInit(&fc_jsonb->root);

					if (JB_ROOT_IS_SCALAR(fc_jsonb))
					{
						(void) JsonbIteratorNext(&fc_it, &fc_jb, true);
						Assert(fc_jb.type == jbvArray);
						(void) JsonbIteratorNext(&fc_it, &fc_jb, true);
						fc_scalar_jsonb = true;
					}
					else
					{
						JsonbIteratorToken fc_type;

						while ((fc_type = JsonbIteratorNext(&fc_it, &fc_jb, false))
							   != WJB_DONE)
						{
							if (fc_type == WJB_END_ARRAY || fc_type == WJB_END_OBJECT ||
								fc_type == WJB_BEGIN_ARRAY || fc_type == WJB_BEGIN_OBJECT)
								fc_result->res = pushJsonbValue(&fc_result->parseState,
															 fc_type, NULL);
							else
								fc_result->res = pushJsonbValue(&fc_result->parseState,
															 fc_type, &fc_jb);
						}
					}
				}
				break;
			default:
				fc_outputstr = OidOutputFunctionCall(fc_outfuncoid, fc_val);
				fc_jb.type = jbvString;
				fc_jb.val.string.len = fc_checkStringLen(strlen(fc_outputstr));
				fc_jb.val.string.val = fc_outputstr;
				break;
		}
	}

	/* 现在将 jb 插入结果，除非我们是递归执行的 */
	if (!fc_is_null && !fc_scalar_jsonb &&
		fc_tcategory >= JSONBTYPE_JSON && fc_tcategory <= JSONBTYPE_JSONCAST)
	{
		/* 工作已递归完成 */
		return;
	}
	else if (fc_result->parseState == NULL)
	{
		/* 单一根标量 */
		JsonbValue	fc_va;

		fc_va.type = jbvArray;
		fc_va.val.array.rawScalar = true;
		fc_va.val.array.nElems = 1;

		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_BEGIN_ARRAY, &fc_va);
		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_ELEM, &fc_jb);
		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_END_ARRAY, NULL);
	}
	else
	{
		JsonbValue *fc_o = &fc_result->parseState->contVal;

		switch (fc_o->type)
		{
			case jbvArray:
				fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_ELEM, &fc_jb);
				break;
			case jbvObject:
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 fc_key_scalar ? WJB_KEY : WJB_VALUE,
											 &fc_jb);
				break;
			default:
				elog(ERROR, "unexpected parent of nested structure");
		}
	}
}

/*
 * 处理数组的单个维度。
 * 如果是最内层维度，输出值；否则递归调用
 * 我们自己来处理下一个维度。
 */
static void fc_array_dim_to_jsonb(JsonbInState *fc_result, int fc_dim, int fc_ndims, int *fc_dims, Datum *fc_vals,
				   bool *fc_nulls, int *fc_valcount, JsonbTypeCategory fc_tcategory,
				   Oid fc_outfuncoid)
{
	int			fc_i;

	Assert(fc_dim < fc_ndims);

	fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_BEGIN_ARRAY, NULL);

	for (fc_i = 1; fc_i <= fc_dims[fc_dim]; fc_i++)
	{
		if (fc_dim + 1 == fc_ndims)
		{
			fc_datum_to_jsonb(fc_vals[*fc_valcount], fc_nulls[*fc_valcount], fc_result, fc_tcategory,
						   fc_outfuncoid, false);
			(*fc_valcount)++;
		}
		else
		{
			fc_array_dim_to_jsonb(fc_result, fc_dim + 1, fc_ndims, fc_dims, fc_vals, fc_nulls,
							   fc_valcount, fc_tcategory, fc_outfuncoid);
		}
	}

	fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_END_ARRAY, NULL);
}

/*
 * 将数组转换为 JSON。
 */
static void fc_array_to_jsonb_internal(Datum fc_array, JsonbInState *fc_result)
{
	ArrayType  *fc_v = DatumGetArrayTypeP(fc_array);
	Oid			fc_element_type = ARR_ELEMTYPE(fc_v);
	int		   *fc_dim;
	int			fc_ndim;
	int			fc_nitems;
	int			fc_count = 0;
	Datum	   *fc_elements;
	bool	   *fc_nulls;
	int16		fc_typlen;
	bool		fc_typbyval;
	char		fc_typalign;
	JsonbTypeCategory fc_tcategory;
	Oid			fc_outfuncoid;

	fc_ndim = ARR_NDIM(fc_v);
	fc_dim = ARR_DIMS(fc_v);
	fc_nitems = ArrayGetNItems(fc_ndim, fc_dim);

	if (fc_nitems <= 0)
	{
		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_BEGIN_ARRAY, NULL);
		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_END_ARRAY, NULL);
		return;
	}

	get_typlenbyvalalign(fc_element_type,
						 &fc_typlen, &fc_typbyval, &fc_typalign);

	fc_jsonb_categorize_type(fc_element_type,
						  &fc_tcategory, &fc_outfuncoid);

	deconstruct_array(fc_v, fc_element_type, fc_typlen, fc_typbyval,
					  fc_typalign, &fc_elements, &fc_nulls,
					  &fc_nitems);

	fc_array_dim_to_jsonb(fc_result, 0, fc_ndim, fc_dim, fc_elements, fc_nulls, &fc_count, fc_tcategory,
					   fc_outfuncoid);

	pfree(fc_elements);
	pfree(fc_nulls);
}

/*
 * 将复合类型 / 记录转换为 JSON。
 */
static void fc_composite_to_jsonb(Datum fc_composite, JsonbInState *fc_result)
{
	HeapTupleHeader fc_td;
	Oid			fc_tupType;
	int32		fc_tupTypmod;
	TupleDesc	fc_tupdesc;
	HeapTupleData fc_tmptup,
			   *fc_tuple;
	int			fc_i;

	fc_td = DatumGetHeapTupleHeader(fc_composite);

	/* 提取行类型信息并找到 tupdesc */
	fc_tupType = HeapTupleHeaderGetTypeId(fc_td);
	fc_tupTypmod = HeapTupleHeaderGetTypMod(fc_td);
	fc_tupdesc = lookup_rowtype_tupdesc(fc_tupType, fc_tupTypmod);

	/* 构建一个临时 HeapTuple 控制结构 */
	fc_tmptup.t_len = HeapTupleHeaderGetDatumLength(fc_td);
	fc_tmptup.t_data = fc_td;
	fc_tuple = &fc_tmptup;

	fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_BEGIN_OBJECT, NULL);

	for (fc_i = 0; fc_i < fc_tupdesc->natts; fc_i++)
	{
		Datum		fc_val;
		bool		fc_isnull;
		char	   *fc_attname;
		JsonbTypeCategory fc_tcategory;
		Oid			fc_outfuncoid;
		JsonbValue	fc_v;
		Form_pg_attribute fc_att = TupleDescAttr(fc_tupdesc, fc_i);

		if (fc_att->attisdropped)
			continue;

		fc_attname = NameStr(fc_att->attname);

		fc_v.type = jbvString;
		/* 这里不需要检查字符串长度 - 不能超过最大名称长度 */
		fc_v.val.string.len = strlen(fc_attname);
		fc_v.val.string.val = fc_attname;

		fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_KEY, &fc_v);

		fc_val = heap_getattr(fc_tuple, fc_i + 1, fc_tupdesc, &fc_isnull);

		if (fc_isnull)
		{
			fc_tcategory = JSONBTYPE_NULL;
			fc_outfuncoid = InvalidOid;
		}
		else
			fc_jsonb_categorize_type(fc_att->atttypid, &fc_tcategory, &fc_outfuncoid);

		fc_datum_to_jsonb(fc_val, fc_isnull, fc_result, fc_tcategory, fc_outfuncoid, false);
	}

	fc_result->res = pushJsonbValue(&fc_result->parseState, WJB_END_OBJECT, NULL);
	ReleaseTupleDesc(fc_tupdesc);
}

/*
 * 将 "val" 的 JSON 文本附加到 "result"。
 *
 * 这只是对 datum_to_jsonb 的一个简单封装。 如果相同的类型将被
 * 多次打印，请避免使用此方法；最好只进行一次 jsonb_categorize_type
 * 查找。
 */

static void add_jsonb(Datum fc_val, bool fc_is_null, JsonbInState *fc_result,
		  Oid fc_val_type, bool fc_key_scalar)
{
	JsonbTypeCategory fc_tcategory;
	Oid			fc_outfuncoid;

	if (fc_val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	if (fc_is_null)
	{
		fc_tcategory = JSONBTYPE_NULL;
		fc_outfuncoid = InvalidOid;
	}
	else
		fc_jsonb_categorize_type(fc_val_type,
							  &fc_tcategory, &fc_outfuncoid);

	fc_datum_to_jsonb(fc_val, fc_is_null, fc_result, fc_tcategory, fc_outfuncoid, fc_key_scalar);
}

/*
 * SQL 函数 to_jsonb(anyvalue)
 */
Datum to_jsonb(PG_FUNCTION_ARGS)
{
	Datum		fc_val = PG_GETARG_DATUM(0);
	Oid			fc_val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
	JsonbInState fc_result;
	JsonbTypeCategory fc_tcategory;
	Oid			fc_outfuncoid;

	if (fc_val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	fc_jsonb_categorize_type(fc_val_type,
						  &fc_tcategory, &fc_outfuncoid);

	memset(&fc_result, 0, sizeof(JsonbInState));

	fc_datum_to_jsonb(fc_val, false, &fc_result, fc_tcategory, fc_outfuncoid, false);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}

/*
 * SQL 函数 jsonb_build_object(variadic "any")
 */
Datum jsonb_build_object(PG_FUNCTION_ARGS)
{
	int			fc_nargs;
	int			fc_i;
	JsonbInState fc_result;
	Datum	   *fc_args;
	bool	   *fc_nulls;
	Oid		   *fc_types;

	/* 构建参数值以构建对象 */
	fc_nargs = extract_variadic_args(fcinfo, 0, true, &fc_args, &fc_types, &fc_nulls);

	if (fc_nargs < 0)
		PG_RETURN_NULL();

	if (fc_nargs % 2 != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("argument list must have even number of elements"),
		/* 翻译者：%s 是 SQL 函数名称 */
				 errhint("The arguments of %s must consist of alternating keys and values.",
						 "jsonb_build_object()")));

	memset(&fc_result, 0, sizeof(JsonbInState));

	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_BEGIN_OBJECT, NULL);

	for (fc_i = 0; fc_i < fc_nargs; fc_i += 2)
	{
		/* 处理键 */
		if (fc_nulls[fc_i])
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("argument %d: key must not be null", fc_i + 1)));

		add_jsonb(fc_args[fc_i], false, &fc_result, fc_types[fc_i], true);

		/* 处理值 */
		add_jsonb(fc_args[fc_i + 1], fc_nulls[fc_i + 1], &fc_result, fc_types[fc_i + 1], false);
	}

	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}

/*
 * jsonb_build_object 的简化情况，其中它获得 0 个参数。
 */
Datum jsonb_build_object_noargs(PG_FUNCTION_ARGS)
{
	JsonbInState fc_result;

	memset(&fc_result, 0, sizeof(JsonbInState));

	(void) pushJsonbValue(&fc_result.parseState, WJB_BEGIN_OBJECT, NULL);
	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}

/*
 * SQL 函数 jsonb_build_array(variadic "any")
 */
Datum jsonb_build_array(PG_FUNCTION_ARGS)
{
	int			fc_nargs;
	int			fc_i;
	JsonbInState fc_result;
	Datum	   *fc_args;
	bool	   *fc_nulls;
	Oid		   *fc_types;

	/* 构建参数值以构建数组 */
	fc_nargs = extract_variadic_args(fcinfo, 0, true, &fc_args, &fc_types, &fc_nulls);

	if (fc_nargs < 0)
		PG_RETURN_NULL();

	memset(&fc_result, 0, sizeof(JsonbInState));

	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_BEGIN_ARRAY, NULL);

	for (fc_i = 0; fc_i < fc_nargs; fc_i++)
		add_jsonb(fc_args[fc_i], fc_nulls[fc_i], &fc_result, fc_types[fc_i], false);

	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_ARRAY, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}

/*
 * jsonb_build_array 的退化情况，参数为 0 个。
 */
Datum jsonb_build_array_noargs(PG_FUNCTION_ARGS)
{
	JsonbInState fc_result;

	memset(&fc_result, 0, sizeof(JsonbInState));

	(void) pushJsonbValue(&fc_result.parseState, WJB_BEGIN_ARRAY, NULL);
	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_ARRAY, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}


/*
 * SQL 函数 jsonb_object(text[])
 *
 * 取一维或二维的文本数组作为 jsonb 对象的名称值对。
 *
 */
Datum jsonb_object(PG_FUNCTION_ARGS)
{
	ArrayType  *fc_in_array = PG_GETARG_ARRAYTYPE_P(0);
	int			fc_ndims = ARR_NDIM(fc_in_array);
	Datum	   *fc_in_datums;
	bool	   *fc_in_nulls;
	int			fc_in_count,
				fc_count,
				fc_i;
	JsonbInState fc_result;

	memset(&fc_result, 0, sizeof(JsonbInState));

	(void) pushJsonbValue(&fc_result.parseState, WJB_BEGIN_OBJECT, NULL);

	switch (fc_ndims)
	{
		case 0:
			goto close_object;
			break;

		case 1:
			if ((ARR_DIMS(fc_in_array)[0]) % 2)
				ereport(ERROR,
						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
						 errmsg("array must have even number of elements")));
			break;

		case 2:
			if ((ARR_DIMS(fc_in_array)[1]) != 2)
				ereport(ERROR,
						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
						 errmsg("array must have two columns")));
			break;

		default:
			ereport(ERROR,
					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
					 errmsg("wrong number of array subscripts")));
	}

	deconstruct_array(fc_in_array,
					  TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_in_datums, &fc_in_nulls, &fc_in_count);

	fc_count = fc_in_count / 2;

	for (fc_i = 0; fc_i < fc_count; ++fc_i)
	{
		JsonbValue	fc_v;
		char	   *fc_str;
		int			fc_len;

		if (fc_in_nulls[fc_i * 2])
			ereport(ERROR,
					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
					 errmsg("null value not allowed for object key")));

		fc_str = TextDatumGetCString(fc_in_datums[fc_i * 2]);
		fc_len = strlen(fc_str);

		fc_v.type = jbvString;

		fc_v.val.string.len = fc_len;
		fc_v.val.string.val = fc_str;

		(void) pushJsonbValue(&fc_result.parseState, WJB_KEY, &fc_v);

		if (fc_in_nulls[fc_i * 2 + 1])
		{
			fc_v.type = jbvNull;
		}
		else
		{
			fc_str = TextDatumGetCString(fc_in_datums[fc_i * 2 + 1]);
			fc_len = strlen(fc_str);

			fc_v.type = jbvString;

			fc_v.val.string.len = fc_len;
			fc_v.val.string.val = fc_str;
		}

		(void) pushJsonbValue(&fc_result.parseState, WJB_VALUE, &fc_v);
	}

	pfree(fc_in_datums);
	pfree(fc_in_nulls);

close_object:
	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}

/*
 * SQL 函数 jsonb_object(text[], text[])
 *
 * 取分开的名称和值文本数组对构造 jsonb 对象。
 */
Datum jsonb_object_two_arg(PG_FUNCTION_ARGS)
{
	ArrayType  *fc_key_array = PG_GETARG_ARRAYTYPE_P(0);
	ArrayType  *fc_val_array = PG_GETARG_ARRAYTYPE_P(1);
	int			fc_nkdims = ARR_NDIM(fc_key_array);
	int			fc_nvdims = ARR_NDIM(fc_val_array);
	Datum	   *fc_key_datums,
			   *fc_val_datums;
	bool	   *fc_key_nulls,
			   *fc_val_nulls;
	int			fc_key_count,
				fc_val_count,
				fc_i;
	JsonbInState fc_result;

	memset(&fc_result, 0, sizeof(JsonbInState));

	(void) pushJsonbValue(&fc_result.parseState, WJB_BEGIN_OBJECT, NULL);

	if (fc_nkdims > 1 || fc_nkdims != fc_nvdims)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (fc_nkdims == 0)
		goto close_object;

	deconstruct_array(fc_key_array,
					  TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_key_datums, &fc_key_nulls, &fc_key_count);

	deconstruct_array(fc_val_array,
					  TEXTOID, -1, false, TYPALIGN_INT,
					  &fc_val_datums, &fc_val_nulls, &fc_val_count);

	if (fc_key_count != fc_val_count)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("mismatched array dimensions")));

	for (fc_i = 0; fc_i < fc_key_count; ++fc_i)
	{
		JsonbValue	fc_v;
		char	   *fc_str;
		int			fc_len;

		if (fc_key_nulls[fc_i])
			ereport(ERROR,
					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
					 errmsg("null value not allowed for object key")));

		fc_str = TextDatumGetCString(fc_key_datums[fc_i]);
		fc_len = strlen(fc_str);

		fc_v.type = jbvString;

		fc_v.val.string.len = fc_len;
		fc_v.val.string.val = fc_str;

		(void) pushJsonbValue(&fc_result.parseState, WJB_KEY, &fc_v);

		if (fc_val_nulls[fc_i])
		{
			fc_v.type = jbvNull;
		}
		else
		{
			fc_str = TextDatumGetCString(fc_val_datums[fc_i]);
			fc_len = strlen(fc_str);

			fc_v.type = jbvString;

			fc_v.val.string.len = fc_len;
			fc_v.val.string.val = fc_str;
		}

		(void) pushJsonbValue(&fc_result.parseState, WJB_VALUE, &fc_v);
	}

	pfree(fc_key_datums);
	pfree(fc_key_nulls);
	pfree(fc_val_datums);
	pfree(fc_val_nulls);

close_object:
	fc_result.res = pushJsonbValue(&fc_result.parseState, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(fc_result.res));
}


/*
 * 解析状态的浅克隆，适用于仅在聚合最终函数中附加值而不是更改它们的场景。
 */
static JsonbParseState *
fc_clone_parse_state(JsonbParseState *fc_state)
{
	JsonbParseState *fc_result,
			   *fc_icursor,
			   *fc_ocursor;

	if (fc_state == NULL)
		return NULL;

	fc_result = palloc(sizeof(JsonbParseState));
	fc_icursor = fc_state;
	fc_ocursor = fc_result;
	for (;;)
	{
		fc_ocursor->contVal = fc_icursor->contVal;
		fc_ocursor->size = fc_icursor->size;
		fc_icursor = fc_icursor->next;
		if (fc_icursor == NULL)
			break;
		fc_ocursor->next = palloc(sizeof(JsonbParseState));
		fc_ocursor = fc_ocursor->next;
	}
	fc_ocursor->next = NULL;

	return fc_result;
}


/*
 * jsonb_agg 聚合函数
 */
Datum jsonb_agg_transfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_oldcontext,
				fc_aggcontext;
	JsonbAggState *fc_state;
	JsonbInState fc_elem;
	Datum		fc_val;
	JsonbInState *fc_result;
	bool		fc_single_scalar = false;
	JsonbIterator *fc_it;
	Jsonb	   *fc_jbelem;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_type;

	if (!AggCheckCallContext(fcinfo, &fc_aggcontext))
	{
		/* 由于内部类型参数，无法直接调用 */
		elog(ERROR, "jsonb_agg_transfn called in non-aggregate context");
	}

	/* 在第一次循环时设置累加器 */

	if (PG_ARGISNULL(0))
	{
		Oid			fc_arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);

		if (fc_arg_type == InvalidOid)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));

		fc_oldcontext = MemoryContextSwitchTo(fc_aggcontext);
		fc_state = palloc(sizeof(JsonbAggState));
		fc_result = palloc0(sizeof(JsonbInState));
		fc_state->res = fc_result;
		fc_result->res = pushJsonbValue(&fc_result->parseState,
									 WJB_BEGIN_ARRAY, NULL);
		MemoryContextSwitchTo(fc_oldcontext);

		fc_jsonb_categorize_type(fc_arg_type, &fc_state->val_category,
							  &fc_state->val_output_func);
	}
	else
	{
		fc_state = (JsonbAggState *) PG_GETARG_POINTER(0);
		fc_result = fc_state->res;
	}

	/* 在正常函数上下文中将参数转换为 jsonb */

	fc_val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);

	memset(&fc_elem, 0, sizeof(JsonbInState));

	fc_datum_to_jsonb(fc_val, PG_ARGISNULL(1), &fc_elem, fc_state->val_category,
				   fc_state->val_output_func, false);

	fc_jbelem = JsonbValueToJsonb(fc_elem.res);

	/* 切换到聚合上下文进行累加操作 */

	fc_oldcontext = MemoryContextSwitchTo(fc_aggcontext);

	fc_it = JsonbIteratorInit(&fc_jbelem->root);

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		switch (fc_type)
		{
			case WJB_BEGIN_ARRAY:
				if (fc_v.val.array.rawScalar)
					fc_single_scalar = true;
				else
					fc_result->res = pushJsonbValue(&fc_result->parseState,
												 fc_type, NULL);
				break;
			case WJB_END_ARRAY:
				if (!fc_single_scalar)
					fc_result->res = pushJsonbValue(&fc_result->parseState,
												 fc_type, NULL);
				break;
			case WJB_BEGIN_OBJECT:
			case WJB_END_OBJECT:
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 fc_type, NULL);
				break;
			case WJB_ELEM:
			case WJB_KEY:
			case WJB_VALUE:
				if (fc_v.type == jbvString)
				{
					/* 在聚合上下文中复制字符串值 */
					char	   *fc_buf = palloc(fc_v.val.string.len + 1);

					snprintf(fc_buf, fc_v.val.string.len + 1, "%s", fc_v.val.string.val);
					fc_v.val.string.val = fc_buf;
				}
				else if (fc_v.type == jbvNumeric)
				{
					/* 数字同理 */
					fc_v.val.numeric =
						DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
															NumericGetDatum(fc_v.val.numeric)));
				}
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 fc_type, &fc_v);
				break;
			default:
				elog(ERROR, "unknown jsonb iterator token type");
		}
	}

	MemoryContextSwitchTo(fc_oldcontext);

	PG_RETURN_POINTER(fc_state);
}

Datum jsonb_agg_finalfn(PG_FUNCTION_ARGS)
{
	JsonbAggState *fc_arg;
	JsonbInState fc_result;
	Jsonb	   *fc_out;

	/* 由于内部类型参数，无法直接调用 */
	Assert(AggCheckCallContext(fcinfo, NULL));

	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();		/* 如果没有输入值则返回空 */

	fc_arg = (JsonbAggState *) PG_GETARG_POINTER(0);

	/*
	 * 我们需要对参数进行浅克隆，以防最终函数被多次调用，这样可以避免更改参数。浅克隆是足够的，因为我们不会更改任何值，只需添加最终数组结束标记。
	 */

	fc_result.parseState = fc_clone_parse_state(fc_arg->res->parseState);

	fc_result.res = pushJsonbValue(&fc_result.parseState,
								WJB_END_ARRAY, NULL);

	fc_out = JsonbValueToJsonb(fc_result.res);

	PG_RETURN_POINTER(fc_out);
}

/*
 * jsonb_object_agg 聚合函数
 */
Datum jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_oldcontext,
				fc_aggcontext;
	JsonbInState fc_elem;
	JsonbAggState *fc_state;
	Datum		fc_val;
	JsonbInState *fc_result;
	bool		fc_single_scalar;
	JsonbIterator *fc_it;
	Jsonb	   *fc_jbkey,
			   *fc_jbval;
	JsonbValue	fc_v;
	JsonbIteratorToken fc_type;

	if (!AggCheckCallContext(fcinfo, &fc_aggcontext))
	{
		/* 由于内部类型参数，无法直接调用 */
		elog(ERROR, "jsonb_object_agg_transfn called in non-aggregate context");
	}

	/* 在第一次循环时设置累加器 */

	if (PG_ARGISNULL(0))
	{
		Oid			fc_arg_type;

		fc_oldcontext = MemoryContextSwitchTo(fc_aggcontext);
		fc_state = palloc(sizeof(JsonbAggState));
		fc_result = palloc0(sizeof(JsonbInState));
		fc_state->res = fc_result;
		fc_result->res = pushJsonbValue(&fc_result->parseState,
									 WJB_BEGIN_OBJECT, NULL);
		MemoryContextSwitchTo(fc_oldcontext);

		fc_arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);

		if (fc_arg_type == InvalidOid)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));

		fc_jsonb_categorize_type(fc_arg_type, &fc_state->key_category,
							  &fc_state->key_output_func);

		fc_arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);

		if (fc_arg_type == InvalidOid)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));

		fc_jsonb_categorize_type(fc_arg_type, &fc_state->val_category,
							  &fc_state->val_output_func);
	}
	else
	{
		fc_state = (JsonbAggState *) PG_GETARG_POINTER(0);
		fc_result = fc_state->res;
	}

	/* 在正常函数上下文中将参数转换为 jsonb */

	if (PG_ARGISNULL(1))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("field name must not be null")));

	fc_val = PG_GETARG_DATUM(1);

	memset(&fc_elem, 0, sizeof(JsonbInState));

	fc_datum_to_jsonb(fc_val, false, &fc_elem, fc_state->key_category,
				   fc_state->key_output_func, true);

	fc_jbkey = JsonbValueToJsonb(fc_elem.res);

	fc_val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);

	memset(&fc_elem, 0, sizeof(JsonbInState));

	fc_datum_to_jsonb(fc_val, PG_ARGISNULL(2), &fc_elem, fc_state->val_category,
				   fc_state->val_output_func, false);

	fc_jbval = JsonbValueToJsonb(fc_elem.res);

	fc_it = JsonbIteratorInit(&fc_jbkey->root);

	/* 切换到聚合上下文进行累加操作 */

	fc_oldcontext = MemoryContextSwitchTo(fc_aggcontext);

	/*
	 * 键应该是标量的，我们应该已经在上面调用 datum_to_jsonb 时检查过，因此我们只需查看这些内容。
	 */

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		switch (fc_type)
		{
			case WJB_BEGIN_ARRAY:
				if (!fc_v.val.array.rawScalar)
					elog(ERROR, "unexpected structure for key");
				break;
			case WJB_ELEM:
				if (fc_v.type == jbvString)
				{
					/* 在聚合上下文中复制字符串值 */
					char	   *fc_buf = palloc(fc_v.val.string.len + 1);

					snprintf(fc_buf, fc_v.val.string.len + 1, "%s", fc_v.val.string.val);
					fc_v.val.string.val = fc_buf;
				}
				else
				{
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
							 errmsg("object keys must be strings")));
				}
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 WJB_KEY, &fc_v);
				break;
			case WJB_END_ARRAY:
				break;
			default:
				elog(ERROR, "unexpected structure for key");
				break;
		}
	}

	fc_it = JsonbIteratorInit(&fc_jbval->root);

	fc_single_scalar = false;

	/*
	 * 值可以是任何东西，包括结构化和空，因此我们像在 json_agg_transfn 中那样处理它们，除了单个标量总是被作为 WJB_VALUE 项推送。
	 */

	while ((fc_type = JsonbIteratorNext(&fc_it, &fc_v, false)) != WJB_DONE)
	{
		switch (fc_type)
		{
			case WJB_BEGIN_ARRAY:
				if (fc_v.val.array.rawScalar)
					fc_single_scalar = true;
				else
					fc_result->res = pushJsonbValue(&fc_result->parseState,
												 fc_type, NULL);
				break;
			case WJB_END_ARRAY:
				if (!fc_single_scalar)
					fc_result->res = pushJsonbValue(&fc_result->parseState,
												 fc_type, NULL);
				break;
			case WJB_BEGIN_OBJECT:
			case WJB_END_OBJECT:
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 fc_type, NULL);
				break;
			case WJB_ELEM:
			case WJB_KEY:
			case WJB_VALUE:
				if (fc_v.type == jbvString)
				{
					/* 在聚合上下文中复制字符串值 */
					char	   *fc_buf = palloc(fc_v.val.string.len + 1);

					snprintf(fc_buf, fc_v.val.string.len + 1, "%s", fc_v.val.string.val);
					fc_v.val.string.val = fc_buf;
				}
				else if (fc_v.type == jbvNumeric)
				{
					/* 数字同理 */
					fc_v.val.numeric =
						DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
															NumericGetDatum(fc_v.val.numeric)));
				}
				fc_result->res = pushJsonbValue(&fc_result->parseState,
											 fc_single_scalar ? WJB_VALUE : fc_type,
											 &fc_v);
				break;
			default:
				elog(ERROR, "unknown jsonb iterator token type");
		}
	}

	MemoryContextSwitchTo(fc_oldcontext);

	PG_RETURN_POINTER(fc_state);
}

Datum jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
{
	JsonbAggState *fc_arg;
	JsonbInState fc_result;
	Jsonb	   *fc_out;

	/* 由于内部类型参数，无法直接调用 */
	Assert(AggCheckCallContext(fcinfo, NULL));

	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();		/* 如果没有输入值则返回空 */

	fc_arg = (JsonbAggState *) PG_GETARG_POINTER(0);

	/*
	 * 我们需要对参数的 res 字段进行浅克隆，以防最终函数被多次调用，这样可以避免更改聚合状态值。浅克隆是足够的，因为我们不会更改任何值，只需添加最终对象结束标记。
	 */

	fc_result.parseState = fc_clone_parse_state(fc_arg->res->parseState);

	fc_result.res = pushJsonbValue(&fc_result.parseState,
								WJB_END_OBJECT, NULL);

	fc_out = JsonbValueToJsonb(fc_result.res);

	PG_RETURN_POINTER(fc_out);
}


/*
 * 从原始标量伪数组 jsonb 中提取标量值。
 */
bool JsonbExtractScalar(JsonbContainer *fc_jbc, JsonbValue *fc_res)
{
	JsonbIterator *fc_it;
	JsonbIteratorToken fc_tok PG_USED_FOR_ASSERTS_ONLY;
	JsonbValue	fc_tmp;

	if (!JsonContainerIsArray(fc_jbc) || !JsonContainerIsScalar(fc_jbc))
	{
		/* 通知调用者关于容器的实际类型 */
		fc_res->type = (JsonContainerIsArray(fc_jbc)) ? jbvArray : jbvObject;
		return false;
	}

	/*
	 * 根标量存储为一个元素的数组，因此我们得到数组，然后是它的第一个（也是唯一的）成员。
	 */
	fc_it = JsonbIteratorInit(fc_jbc);

	fc_tok = JsonbIteratorNext(&fc_it, &fc_tmp, true);
	Assert(fc_tok == WJB_BEGIN_ARRAY);
	Assert(fc_tmp.val.array.nElems == 1 && fc_tmp.val.array.rawScalar);

	fc_tok = JsonbIteratorNext(&fc_it, fc_res, true);
	Assert(fc_tok == WJB_ELEM);
	Assert(IsAJsonbScalar(fc_res));

	fc_tok = JsonbIteratorNext(&fc_it, &fc_tmp, true);
	Assert(fc_tok == WJB_END_ARRAY);

	fc_tok = JsonbIteratorNext(&fc_it, &fc_tmp, true);
	Assert(fc_tok == WJB_DONE);

	return true;
}

/*
 * 发出正确的、可翻译的转换错误信息
 */
static void fc_cannotCastJsonbValue(enum jbvType fc_type, const char *fc_sqltype)
{
	static const struct
	{
		enum jbvType type;
		const char *msg;
	}
				fc_messages[] =
	{
		{jbvNull, gettext_noop("cannot cast jsonb null to type %s")},
		{jbvString, gettext_noop("cannot cast jsonb string to type %s")},
		{jbvNumeric, gettext_noop("cannot cast jsonb numeric to type %s")},
		{jbvBool, gettext_noop("cannot cast jsonb boolean to type %s")},
		{jbvArray, gettext_noop("cannot cast jsonb array to type %s")},
		{jbvObject, gettext_noop("cannot cast jsonb object to type %s")},
		{jbvBinary, gettext_noop("cannot cast jsonb array or object to type %s")}
	};
	int			fc_i;

	for (fc_i = 0; fc_i < lengthof(fc_messages); fc_i++)
		if (fc_messages[fc_i].type == fc_type)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg(fc_messages[fc_i].msg, fc_sqltype)));

	/* 应该无法到达 */
	elog(ERROR, "unknown jsonb type: %d", (int) fc_type);
}

Datum jsonb_bool(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvBool)
		fc_cannotCastJsonbValue(fc_v.type, "boolean");

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_BOOL(fc_v.val.boolean);
}

Datum jsonb_numeric(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Numeric		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "numeric");

	/*
	 * v.val.numeric 指向 jsonb 主体，因此我们需要进行一个副本来返回
	 */
	fc_retValue = DatumGetNumericCopy(NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_NUMERIC(fc_retValue);
}

Datum jsonb_int2(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Datum		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "smallint");

	fc_retValue = DirectFunctionCall1(numeric_int2,
								   NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_DATUM(fc_retValue);
}

Datum jsonb_int4(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Datum		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "integer");

	fc_retValue = DirectFunctionCall1(numeric_int4,
								   NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_DATUM(fc_retValue);
}

Datum jsonb_int8(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Datum		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "bigint");

	fc_retValue = DirectFunctionCall1(numeric_int8,
								   NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_DATUM(fc_retValue);
}

Datum jsonb_float4(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Datum		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "real");

	fc_retValue = DirectFunctionCall1(numeric_float4,
								   NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_DATUM(fc_retValue);
}

Datum jsonb_float8(PG_FUNCTION_ARGS)
{
	Jsonb	   *fc_in = PG_GETARG_JSONB_P(0);
	JsonbValue	fc_v;
	Datum		fc_retValue;

	if (!JsonbExtractScalar(&fc_in->root, &fc_v) || fc_v.type != jbvNumeric)
		fc_cannotCastJsonbValue(fc_v.type, "double precision");

	fc_retValue = DirectFunctionCall1(numeric_float8,
								   NumericGetDatum(fc_v.val.numeric));

	PG_FREE_IF_COPY(fc_in, 0);

	PG_RETURN_DATUM(fc_retValue);
}
